package io.task.message.socket.spi.server;

import io.task.message.socket.Node;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.util.concurrent.TimeUnit;

@Slf4j
@Setter
@Getter
public class Server {

    private ServerConfig serverConfig;
    private AsynchronousServerSocketChannel serverSocketChannel;
    private AsynchronousChannelGroup channelGroup = null;
    private Node serverNode;
    private boolean isWaitingStop = false;
    private final boolean checkLastVersion = true;


    public Server(ServerConfig serverConfig) {
        super();
        this.serverConfig = serverConfig;
    }


    public void start(String serverIp, int serverPort) throws IOException {
        long start = System.currentTimeMillis();
        this.serverNode = new Node(serverIp, serverPort);
        channelGroup = AsynchronousChannelGroup.withThreadPool(serverConfig.groupExecutor);
        serverSocketChannel = AsynchronousServerSocketChannel.open(channelGroup);

        serverSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
        serverSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 64 * 1024);

        InetSocketAddress listenAddress = null;

        if (serverIp != null) {
            listenAddress = new InetSocketAddress(serverPort);
        } else {
            listenAddress = new InetSocketAddress(serverIp, serverPort);
        }

        serverSocketChannel.bind(listenAddress, 0);

        AcceptCompletionHandler acceptCompletionHandler = serverConfig.getAcceptCompletionHandler();
        serverSocketChannel.accept(this, acceptCompletionHandler);

        serverConfig.startTime = System.currentTimeMillis();


    }

    public boolean stop() {
        isWaitingStop = true;
        boolean ret = true;

        try {
            channelGroup.shutdownNow();
        } catch (Exception e) {
            log.error("channelGroup.shutdownNow()时报错", e);
        }

        try {
            serverSocketChannel.close();
        } catch (Exception e1) {
            log.error("serverSocketChannel.close()时报错", e1);
        }

        try {
            serverConfig.groupExecutor.shutdown();
        } catch (Exception e1) {
            log.error(e1.toString(), e1);
        }
        try {
            serverConfig.tioExecutor.shutdown();
        } catch (Exception e1) {
            log.error(e1.toString(), e1);
        }

        serverConfig.setStopped(true);
        try {
            ret = ret && serverConfig.groupExecutor.awaitTermination(6000, TimeUnit.SECONDS);
            ret = ret && serverConfig.tioExecutor.awaitTermination(6000, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            log.error(e.getLocalizedMessage(), e);
        }

        log.info(this.serverNode + " stopped");
        return ret;
    }


}
